home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / gopher1.12 / gopherd / ftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-11  |  13.1 KB  |  524 lines

  1. /********************************************************************
  2.  * $Author: lindner $
  3.  * $Revision: 1.2 $
  4.  * $Date: 1993/01/11 23:18:09 $
  5.  * $Source: /home/mudhoney/GopherSrc/release1.11/gopherd/RCS/ftp.c,v $
  6.  * $Status: $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: ftp.c
  14.  * Routines to translate gopher protocol to ftp protocol.
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: ftp.c,v $
  18.  * Revision 1.2  1993/01/11  23:18:09  lindner
  19.  * Changed password to be the host of the remote client, not the gateway.
  20.  *
  21.  * Revision 1.1  1992/12/10  23:13:27  lindner
  22.  * gopher 1.1 release
  23.  *
  24.  *
  25.  *********************************************************************/
  26.  
  27.  
  28. /* -------------------------------------------------
  29.  *    g2fd.c          Gopher to FTP gateway daemon.
  30.  *    Version 0.3 Hacked up: April 1992.  Farhad Anklesaria.
  31.  *    Based on a Perl story by John Ladwig.
  32.  *    Based on a Perl story by Farhad Anklesaria.
  33.  *
  34.  *      Modified by Greg Smith, Bucknell University, 24 Nov 1992
  35.  *      to handle multiline status replies.
  36.  *
  37.  ---------------------------------------------------- */
  38.  
  39. #include "gopherd.h"
  40. #include <signal.h>
  41.  
  42. #include <stdio.h>
  43.  
  44.  
  45. #define GFILE    0        /* Gopher item types */
  46. #define GDIR    1
  47. #define GBINHEX    4
  48. #define GDOSB    5
  49. #define GUNIXB    9
  50. #define GIMAGE  "I"
  51. #define GSOUND  "s"
  52.  
  53. #define SLEN    255    /* Generic small buffer length */
  54. #define    TMOUT    180    /* 3 minutes is plenty long enough */
  55.  
  56. int     GLOBALsockfd;   /* For cleanup */
  57. char    *appname;
  58. char    ftptmp[SLEN] = LIST;
  59. char    query[BUFSIZ];                /* input redirected by inetd */
  60. char     *host, *thing;                /* pointers into query */
  61. int    gettingFile = 1;
  62. int    gettingBinary = 0;
  63. int    childpid;
  64.  
  65. /*** Some forward declarations ***/
  66. boolean NotText();
  67. int     Abort();
  68. boolean IsBinaryType();
  69. void    GenerateUniqueFiles();
  70. void    GopherType();
  71. void    Cleanup();
  72. void    RoundEmUp();
  73. void    FailErr();
  74. int     getreply();
  75. /**************************/
  76.  
  77. int
  78. getreply(theStream,inputline,maxlen)
  79.   int theStream;
  80.   char *inputline;
  81.   int maxlen;
  82. {
  83.      int code = 0;
  84.      char origcode[4];
  85.      
  86.  
  87.      readline(theStream, inputline, maxlen);
  88.      if (DEBUG) printf(inputline);
  89.      strncpy(origcode, inputline, 3);  /*** Stash away the original code ***/
  90.  
  91.      while (inputline[3] == '-') {
  92.       if (readline(theStream, inputline, maxlen)<=0)
  93.            return(-1);
  94.       if (DEBUG) printf(inputline);
  95.  
  96.       if (!isdigit(inputline[0]) && !isdigit(inputline[1]) &&
  97.           !isdigit(inputline[2]))
  98.            inputline[3] = '-';
  99.       else
  100.            /*** Keep going if response code isn't the same as original **/
  101.            if (strncmp(origcode, inputline, 3) != 0)
  102.             inputline[3] = '-';
  103.      }
  104.      return (0);
  105. }
  106.  
  107. void
  108. SendFtpQuery(sockfd, query)
  109.   char *query;
  110. {
  111.      int       sLen, termCh;
  112.      char      *at, *cp;
  113.      char      inputline[512];
  114.      char      ipnum[64];
  115.      char      buf[1600];     /*** Nice MTU size ***/
  116.      int       tmpfd;
  117.      int       ftp_control, ftp_data;
  118.      int       ftp_dataport, nRead;
  119.      GopherObj *gs;
  120.  
  121.      /*** hook onto the gs code to do our ftp socket connects ***/
  122.      gs = GSnew();
  123.  
  124.      /** Get ready for some cleanup action **/
  125.      signal(SIGPIPE, Cleanup);
  126.      signal(SIGINT, Cleanup);
  127.      signal(SIGALRM, Cleanup);
  128.  
  129.      if (DEBUG)
  130.       printf("The full query was %s\n", query);
  131.      
  132.      if ((sLen = strlen(query)) <= 2) Abort(sockfd,"No host name specified.");
  133.      host = query;
  134.      at = strchr(query, '@');
  135.      
  136.      if (at == NULL) 
  137.       Abort(sockfd, "Not a valid ftp query.");
  138.      
  139.      GenerateUniqueFiles(ftptmp);
  140.      tmpfd = uopen(ftptmp, O_RDWR|O_CREAT,0755);
  141.      
  142.      if (tmpfd < 0)
  143.       Abort(sockfd, "Sorry, out of tmp transfer space!");
  144.  
  145.      thing = at + 1;
  146.      *at = '\0';             /*Sneakily chop it into two strings*/
  147.  
  148.      sLen = strlen(thing);
  149.      termCh = thing[sLen - 1];            /* Grab possible end char: / etc */
  150.      
  151.      if ((termCh == '*') || (termCh == '@'))  /*  || (termCh == '/')  */
  152.       thing[sLen - 1] = '\0';
  153.      
  154.      if (DEBUG)
  155.       printf("At this point host: %s   thing: %s\n", host, thing);
  156.      
  157.  
  158.  
  159.      /*** Open an ftp control connection ***/
  160.      GSsetHost(gs, host);
  161.      GSsetPort(gs, 21);
  162.      
  163.      ftp_control = GSconnect(gs);
  164.      if (ftp_control < 0)
  165.       Abort(sockfd, "unable to connect to ftp server!");
  166.  
  167.      /*** Strip off the connection message ***/
  168.      getreply(ftp_control,inputline,sizeof inputline);
  169.  
  170.      if (*inputline != '2')
  171.       /*** Some sort of error, urg! ***/
  172.       Abort(sockfd, inputline +3);
  173.  
  174.      /*** Send username ***/
  175.      writestring(ftp_control, "USER anonymous\r\n");
  176.  
  177.      getreply(ftp_control,inputline,sizeof inputline);
  178.  
  179.      if (*inputline != '3')
  180.       /*** Some sort of error, urg! ***/
  181.       Abort(sockfd, inputline +3);
  182.  
  183.      /** Send password***/
  184.      writestring(ftp_control, "PASS -gopher@");
  185.      inet_netnames(sockfd, inputline, ipnum);
  186.      writestring(ftp_control, inputline);
  187.      writestring(ftp_control, "\r\n");
  188.      if (DEBUG) printf("Password was -gopher@%s\n", inputline);
  189.      getreply(ftp_control,inputline,sizeof inputline);
  190.  
  191.      if (*inputline != '2')
  192.       /*** Some sort of error, urg! ***/
  193.       Abort(sockfd, inputline +3);
  194.  
  195.      /**** Send PASV and set up the data port ***/
  196.      writestring(ftp_control, "PASV\r\n");
  197.  
  198.      getreply(ftp_control,inputline,sizeof inputline);
  199.  
  200.      if (strncmp(inputline, "227", 3))
  201.       Abort(sockfd,inputline +3);
  202.      
  203.      /*** Find out the port number of the data connection ***/
  204.      inputline[strlen(inputline)] = '\0';  /** Zap the right paren **/
  205.      cp = strrchr(inputline, ',');         /** lower order octet **/
  206.      if (cp == NULL)  Abort(sockfd,"PASV failed- cannot ftp!");
  207.      *cp = '\0';
  208.      cp ++;
  209.      ftp_dataport = atoi(cp);
  210.  
  211.      cp = strrchr(inputline, ',');         /** upper octet **/
  212.      if (cp == NULL)  Abort(sockfd,"PASV failed- cannot ftp!");
  213.      *cp = '\0';
  214.      cp ++;
  215.      ftp_dataport = atoi(cp) * 256 + ftp_dataport;
  216.      if (DEBUG) printf("Data port is %d\n", ftp_dataport);
  217.  
  218.      GSsetPort(gs, ftp_dataport);
  219.      ftp_data = GSconnect(gs);
  220.      if (ftp_data < 0)
  221.       Abort(sockfd,"Unable to establish data connection!");
  222.  
  223.      
  224.      if (termCh == '/') {    /* We have a directory */
  225.       gettingFile = 0;
  226.  
  227.       writestring(ftp_control, "NLST -LF ");
  228.       if (strlen(thing) > 0)
  229.            writestring(ftp_control, thing);
  230.       writestring(ftp_control, "\r\n");
  231.  
  232.       getreply(ftp_control,inputline,sizeof inputline);
  233.  
  234.       if (*inputline != '1')
  235.            Abort(sockfd,inputline + 4);
  236.      }
  237.      else {                    /* We have a file */
  238.       gettingFile = 1;
  239.       if (gettingBinary = IsBinaryType(thing))  {
  240.            writestring(ftp_control, "TYPE I\r\n");
  241.            getreply(ftp_control,inputline,sizeof inputline);
  242.            if (*inputline != '2')
  243.             Abort(sockfd,"Unable to transfer files in binary");
  244.       }
  245.       writestring(ftp_control, "RETR ");
  246.       writestring(ftp_control, thing);
  247.       writestring(ftp_control, "\r\n");
  248.  
  249.       getreply(ftp_control,inputline,sizeof inputline);
  250.       if (*inputline != '1')
  251.            Abort(sockfd,inputline + 4);
  252.      }
  253.  
  254.      /*** Transfer the data... ***/
  255.      while ((nRead = read(ftp_data, buf, sizeof buf)) > 0)
  256.       writen(tmpfd, buf, nRead);
  257.  
  258.      close(ftp_data);
  259.      
  260.      getreply(ftp_control,inputline,sizeof inputline);
  261.  
  262.      if (*inputline != '2')
  263.       Abort(sockfd,inputline + 3);
  264.  
  265.      writestring(ftp_control, "QUIT\r\n");
  266.  
  267.      getreply(ftp_control,inputline,sizeof inputline);
  268.  
  269.      if (*inputline != '2')
  270.       Abort(sockfd,inputline + 3);
  271.  
  272.      close(ftp_control);
  273. }
  274.  
  275. /*--------------------------------*/
  276. void
  277. TranslateResults(sockfd)
  278.   int sockfd;
  279. {
  280.      FILE  *fp, *OpenOrDie();
  281.      char  buf[BUFSIZ], theName[SLEN];
  282.      int   fd, nRead, checkIt;
  283.      char  outputline[512];
  284.      
  285.      checkIt = 1;
  286.      
  287.      signal(SIGPIPE, Cleanup);
  288.      signal(SIGINT, Cleanup);
  289.  
  290.      if (gettingFile) {
  291.       if (gettingBinary) {                /* icky binary file */
  292.            if (DEBUG)
  293.             printf("Whoa!  That's a binary file\n");
  294.            fp = OpenOrDie(ftptmp, "r");
  295.            fd = fileno(fp);
  296.            
  297.            if (DEBUG)
  298.             printf("fd %d\n",fd);
  299.            while ((nRead = read(fd, buf, sizeof buf)) > 0)
  300.                     writen(sockfd, buf, nRead);
  301.            
  302.            writen(sockfd, buf, nRead);
  303.            fclose(fp);
  304.       } else {            /* must be a nice texty file */
  305.            fp = OpenOrDie(ftptmp, "r");
  306.            while (fgets(buf, sizeof buf, fp) != NULL) {
  307.             if (checkIt) { /* Just peek at it once */
  308.              checkIt = 0;
  309.              if (NotText(buf)) {
  310.                   fclose(fp);
  311.                   Abort(sockfd,"Sorry.  File does not appear to contain text.");
  312.              }
  313.             }
  314.             ZapCRLF(buf);
  315.             FailErr(writestring(sockfd, buf));
  316.             FailErr(writestring(sockfd, "\r\n"));
  317.            }
  318.            fclose(fp);
  319.            FailErr(writestring(sockfd,".\r\n"));
  320.       }
  321.      } else {                       /* Must be a directory */
  322.       fp = OpenOrDie(ftptmp, "r");
  323.       while (fgets(buf, sizeof buf, fp) != NULL) {
  324.            ZapCRLF(buf);
  325.            GopherType(buf, theName);
  326.            sprintf(outputline, "%s\tftp:%s@%s%s\t%s\t%d\r\n", theName,
  327.                host, thing, buf, Zehostname, GopherPort);
  328.            FailErr(writestring(sockfd, outputline));
  329.       }
  330.       fclose(fp);
  331.       FailErr(writestring(sockfd, ".\r\n"));
  332.      }
  333.  
  334.      Cleanup();
  335. }
  336.  
  337. /*--------------------------------*/
  338.  
  339. FILE *OpenOrDie(file, mode)
  340.   char *file, *mode;
  341. {
  342.      FILE *fp, *fopen();
  343.      if ((fp = ufopen(file, mode,0755)) != NULL) {
  344.       return(fp);
  345.      } else {
  346.       Cleanup();
  347.       exit(-1);
  348.      }
  349.      return(NULL);  /** Shouldn't get here **/
  350. }
  351.  
  352.  
  353. /*--------------------------------*/
  354. boolean
  355. NotText(buf)
  356.   char * buf;
  357. {
  358.      int max;   char *c;
  359.      
  360.      if ((max = strlen(buf)) >= (BUFSIZ - 50)) max = BUFSIZ - 50;
  361.      for (c = buf; c < (buf + max); c++) {
  362.       if (*c > '~') return(TRUE);
  363.      }
  364.      return(FALSE);
  365. }
  366.  
  367. /*--------------------------------*/
  368.  
  369. int
  370. Abort(sockfd, complaint)
  371.   int sockfd;
  372.   char *complaint;
  373. {
  374.      char errmsg[512];
  375.      sprintf(errmsg, "3 Error: %s\r\n.\r\n", complaint); 
  376.      writestring(sockfd, errmsg);
  377.      fflush(stdout);
  378.      Cleanup();
  379.      exit(1);
  380. }
  381.  
  382. /*--------------------------------*/
  383.  
  384. boolean
  385. IsBinaryType(thing)
  386.   char *thing;
  387. {
  388.      static char *binExt[] = {
  389.       ".zip", ".zoo", ".arj", ".arc", ".lzh", ".hyp", ".pak", ".exe", ".com",
  390.       ".ps", ".gif", ".pict", ".pct", ".tiff", ".tif", ".tar", ".Z", ".pict", ".au"
  391.       };
  392.      
  393.      int extType, i;
  394.      
  395.      for (extType = 0; extType < 19; extType++) { 
  396.       i = strcasecmp(thing + strlen(thing) - strlen(binExt[extType]),
  397.              binExt[extType]);
  398.       if (i == 0) return(TRUE);
  399.      }
  400.      return(FALSE);
  401.      
  402. }
  403.  
  404. /*--------------------------------*/
  405.  
  406. void
  407. GenerateUniqueFiles(tmpList)
  408.   char *tmpList;
  409. {
  410.      char *s;
  411.      int pid;
  412.      
  413.      pid = getpid();
  414.      s = strchr(tmpList, '+');
  415.      sprintf(s, "%d", pid);
  416. }
  417.  
  418. /*--------------------------------*/
  419.  
  420. void
  421. GopherType(buf, theName)
  422.   char *buf, *theName;
  423. {
  424.      static char ext4[] = ".hqx";
  425.      static char *exts[] = {".au", ".snd"};
  426.      static char *extI[] = {".gif", ".pict", ".tiff", ".tif", ".pcx"};
  427.      static char *ext5[] = {".zip", ".zoo", ".arj", ".arc", ".lzh", ".hyp", 
  428.                  ".pak", ".exe", ".com", ".ps", ".pct"};
  429.      static char *ext9[] = {".tar", ".Z"};
  430.      int extType, i, last;
  431.      char    tmpName[SLEN];    
  432.      
  433.      last = strlen(buf) -1;
  434.  
  435.      strcpy(tmpName, buf);
  436.      if (buf[last] == '/') {
  437.       tmpName[last] = '\0';
  438.       sprintf(theName, "%d%s", GDIR, tmpName);
  439.       return;
  440.      }
  441.      if ((buf[last] == '*') || (buf[last] == '@')) {    /* Hack out * and @ */
  442.       buf[last] = '\0';
  443.       tmpName[last] = '\0';
  444.      }
  445.      
  446.      /* At this point we're looking at a file */
  447.      if (strcasecmp(buf + strlen(buf) - strlen(ext4), ext4) == 0) { /* BinHex? */
  448.       sprintf(theName, "%d%s", GBINHEX, tmpName);
  449.       return;
  450.      }
  451.      
  452.      for (extType = 0; extType < 11; extType++) {  /* PC garbage? */ 
  453.       i = strcasecmp(buf + strlen(buf) - strlen(ext5[extType]), 
  454.              ext5[extType]);
  455.       if (i == 0) {
  456.            sprintf(theName, "%d%s", GDOSB, tmpName);
  457.            return;
  458.       }
  459.      }
  460.      
  461.      for (extType = 0; extType < 2; extType++) {    /* unix binary? */ 
  462.       i = strcasecmp(buf + strlen(buf) - strlen(ext9[extType]), 
  463.              ext9[extType]);
  464.       if (i == 0) {
  465.            sprintf(theName, "%d%s", GUNIXB, tmpName);
  466.            return;
  467.       }
  468.      }
  469.  
  470.      for (extType = 0; extType < 5; extType++) {  /** Image? **/
  471.       i = strcasecmp(buf + strlen(buf) - strlen(extI[extType]), 
  472.              extI[extType]);
  473.       if (i == 0) {
  474.            sprintf(theName, "%s%s", GIMAGE, tmpName);
  475.            return;
  476.       }
  477.      }      
  478.  
  479.      for (extType = 0; extType < 2; extType++) {  /** Image? **/
  480.       i = strcasecmp(buf + strlen(buf) - strlen(exts[extType]), 
  481.              exts[extType]);
  482.       if (i == 0) {
  483.            sprintf(theName, "%s%s", GSOUND, tmpName);
  484.            return;
  485.       }
  486.      }      
  487.      
  488.      sprintf(theName, "%d%s", GFILE, tmpName);
  489.      return;        /* Some other and hopefully text file */
  490. }
  491.  
  492. /*--------------------------------*/
  493.  
  494. void
  495. Cleanup()
  496. {
  497.      unlink(ftptmp);
  498.      if (DEBUG)
  499.       printf("Cleaning up %s\n", ftptmp);
  500.  
  501.      exit(1);
  502. }
  503.  
  504. /*--------------------------------*/
  505. void
  506. RoundEmUp()
  507. {
  508.      
  509.      kill(childpid, SIGKILL);
  510.      Cleanup();
  511. }
  512.  
  513. /*--------------------------------*/
  514. void
  515. FailErr(result)
  516.   int result;
  517. {
  518.      if (result < 0) {
  519.       Cleanup();
  520.      }
  521. }
  522.  
  523. /*--------------------------------*/
  524.